#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#include "scm.h"
#include "stack.h"

scm vm_stack[VM_STACK_SIZE] = { 0 };
scm vm_stack_ptr = 0;
scm vm_stack_base_ptr = 0;

void stack_push(scm obj) {
  if(vm_stack_ptr < VM_STACK_SIZE) {
    vm_stack[vm_stack_ptr++] = obj;
  }
  else {
    fprintf(stderr, "STACK OVERFLOW!\n");
    exit(-1);
  }
}

scm stack_pop() {
  scm result;
  
  if(vm_stack_ptr > 0) {
    vm_stack_ptr--;
    result = vm_stack[vm_stack_ptr];
    vm_stack[vm_stack_ptr] = 0;
    return result;
  }
  else {
    fprintf(stderr, "STACK UNDERFLOW!\n");
    exit(-1);
  }
}

void stack_grow(scm n) {
  int i;
  
  for(i = 0; i < n; i++) {
    stack_push(0);
  }
}

scm vm_stack_top_ref(scm i) {
  assert(vm_stack_ptr - 1 - i >= vm_stack_base_ptr);
  return vm_stack[vm_stack_ptr - 1 - i];
}

void vm_set_stack_top(scm i, scm obj) {
  assert(vm_stack_ptr - 1 - i >= vm_stack_base_ptr);
  vm_stack[vm_stack_ptr - 1 - i] = obj;
}

scm vm_stack_base_ref(scm i) {
  assert(vm_stack_base_ptr + i < vm_stack_ptr);
  return vm_stack[vm_stack_base_ptr + i];
}

void vm_set_stack_base(scm i, scm obj) {
  assert(vm_stack_base_ptr + i < vm_stack_ptr);
  vm_stack[vm_stack_base_ptr + i] = obj;
}

